package course.ya.doc.from.code.model.lexer.project;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;

public class Scanner {
    
    private String fileName;
    private String sourceCode;
    private SyntaxTree resultTree;
    private String useDelimiters;
    private String[] delimiters;

    public Scanner(String data, String[] delimiters) {
        this.fileName = "";
        this.resultTree = new SyntaxTree();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < delimiters.length; i++) {
            sb.append(delimiters[i]);
        }
        this.useDelimiters = sb.toString();
        this.delimiters = delimiters;
        this.sourceCode = data;
    }

    public Scanner(String nameOfFile, SyntaxTree tree, String[] delimiters) throws IOException {
        this.fileName = nameOfFile;
        this.resultTree = tree;
        StringBuilder sbuilder = new StringBuilder();
        for (int i = 0; i < delimiters.length; i++) {
            sbuilder.append(delimiters[i]);
        }
        this.useDelimiters = sbuilder.toString();
        this.delimiters = delimiters;
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append("\n");
        }

        reader.close();
        this.sourceCode = sb.toString();
    }

    public void scan() {
        String token = null;
        String nextToken = null;
        int low = 0;
        StringTokenizer st = new StringTokenizer(sourceCode, useDelimiters, true);

        while (st.hasMoreTokens()) {
            token = st.nextToken();
            token = findComment(token);
            if (st.hasMoreTokens()) {
                nextToken = st.nextToken();
            } else {
                nextToken = this.delimiters[0];
            }
            if (findAnomaly(token) == 3) {
                if (token.indexOf(":") == -1) {
                    StringBuilder sb = new StringBuilder();
                    int balans = 0;
                    do {
                        if (token.indexOf("(") > 0) {
                            balans++;
                        } else {
                            if (token.indexOf(")") > 0) {
                                balans--;
                            }
                        }
                        if (!token.equals(this.delimiters[0])) {
                            sb.append(token).append(this.delimiters[0]);
                        }
                        token = st.nextToken();
                        token = token.trim();

                    } while (balans != 0);
                    nextToken = token;
                    token = sb.toString();
                    token = token.substring(0, token.length() - 1);
                    token = token.trim();
                }
            }
            if ((findAnomaly(token) == 1 || findAnomaly(token) == 2 || findAnomaly(token) == 3) && nextToken.equals(delimiters[0])) {
                restructAnomaly(token);
            } else {
                if (nextToken.equals(delimiters[0])) {
                    if (!token.equals("")) {
                        this.resultTree.insert(token, false, false);
                    }
                } else {
                    if (nextToken.equals(delimiters[1])) {
                        low++;
                        if (!token.equals("")) {
                            this.resultTree.insert(token, false, true);
                        }
                    } else {
                        if (nextToken.equals(delimiters[2])) {
                            low--;
                            if (!token.equals("")) {
                                this.resultTree.insert(token, false, false);
                            }
                            this.resultTree.jumpUp();
                        }
                    }
                }
            }
        }
    }

    private String findComment(String lex) {
        lex = lex.trim();
        if (!lex.equals("")) {
            char[] array = lex.toCharArray();
            int i = 0;
            if (array[0] == '/' && array[1] == '/') {
                while (i < lex.length() && array[i] != '\n') {
                    i++;
                }
                String comment = lex.substring(0, i);

                this.resultTree.insert(comment, false, false);
                lex = lex.substring(i, lex.length());
                lex.trim();
            } else {
                if (array[0] == '/' && array[1] == '*') {
                    while (array[i] != '*' && array[i + 1] != '/' && i < lex.length()) {
                        i++;
                    }
                    String comment = lex.substring(0, i);
                    this.resultTree.insert(comment, false, false);
                    lex = lex.substring(i, lex.length());
                    lex.trim();
                }
            }
        }
        return lex;
    }

    private int findAnomaly(String word) {
        StringTokenizer st = new StringTokenizer(word, " ()");
        String analys = null;
        if (st.hasMoreTokens()) {
            analys = st.nextToken();
            analys = analys.trim();
        }
        if (analys != null) {
            if (analys.equals("if")) {
                return 1;
            }
            if (analys.equals("while")) {
                return 2;
            }
            if (analys.equals("for")) {
                return 3;
            }
        }
        return 0;
    }

    private void restructAnomaly(String token) {
        int balans = 0;
        boolean flag = false;
        char[] tokens = token.toCharArray();
        int index = 0;
        for (index = 0; index < tokens.length; index++) {
            if (tokens[index] == '(') {
                balans++;
                flag = true;
            } else {
                if (tokens[index] == ')') {
                    balans--;
                }
            }
            if (balans == 0 && flag == true) {
                break;
            }
        }
        String startToken = token.substring(0, index + 1);
        startToken = startToken.trim();
        String endToken = token.substring(index + 1);
        endToken = endToken.trim();
        this.resultTree.insert(startToken, false, true);
        if (!endToken.equals("")) {
            this.resultTree.insert(endToken, false, false);
            this.resultTree.jumpUp();
        }
    }

    public SyntaxTree returnTree() {
        return this.resultTree;
    }
}
